/*
 * Copyright 2011 Katsunori Koyanagi
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package sweezy.core.log
{

	public class LogWriter implements ILogWriter
	{

		private var _debug:Boolean;

		private var _error:Boolean;

		private var _fatal:Boolean;

		private var _filters:Array;

		private var _format:String;

		private var _formatter:LogFormatter;

		private var _info:Boolean;

		private var _level:uint;

		private var _warn:Boolean;

		public function LogWriter()
		{
		}

		public function accept(category:String, level:uint):Boolean
		{
			if (((1 << level) & _level) === 0)
			{
				return false;
			}

			if (_filters === null || _filters.length === 0)
			{
				return true;
			}

			for each (var filter:String in _filters)
			{
				if (filter === null)
				{
					continue;
				}
				if (category.indexOf(filter) === 0)
				{
					return true;
				}
			}

			return false;
		}

		public function get debug():Boolean
		{
			return _debug;
		}

		public function set debug(value:Boolean):void
		{
			if (_debug === value)
			{
				return;
			}

			_debug = value;

			if (value)
			{
				_level |= (1 << LogLevel.DEBUG);
			}
			else
			{
				_level &= ~(1 << LogLevel.DEBUG);
			}

			Logger.clearInternalCache();
		}

		public function get error():Boolean
		{
			return _error;
		}

		public function set error(value:Boolean):void
		{
			if (_error === value)
			{
				return;
			}

			if (value)
			{
				_level |= (1 << LogLevel.ERROR);
			}
			else
			{
				_level &= ~(1 << LogLevel.ERROR);
			}

			_error = value;
			Logger.clearInternalCache();
		}

		public function get fatal():Boolean
		{
			return _fatal;
		}

		public function set fatal(value:Boolean):void
		{
			if (_fatal === value)
			{
				return;
			}

			if (value)
			{
				_level |= (1 << LogLevel.FATAL);
			}
			else
			{
				_level &= ~(1 << LogLevel.FATAL);
			}

			_fatal = value;
			Logger.clearInternalCache();
		}

		public function get filters():Array
		{
			return _filters === null ? null : _filters.slice();
		}

		public function set filters(value:Array):void
		{
			if (_filters === value)
			{
				return;
			}
			if (value !== null)
			{
				value = value.slice();
			}

			_filters = value;
			Logger.clearInternalCache();
		}

		public function get format():String
		{
			return _format;
		}

		public function set format(value:String):void
		{
			if (value === _format)
			{
				return;
			}

			_format = value;
			_formatter = null;
		}

		public function get info():Boolean
		{
			return _info;
		}

		public function set info(value:Boolean):void
		{
			if (_info === value)
			{
				return;
			}

			if (value)
			{
				_level |= (1 << LogLevel.INFO);
			}
			else
			{
				_level &= ~(1 << LogLevel.INFO);
			}

			_info = value;
			Logger.clearInternalCache();
		}

		public function setAllLevels(enabled:Boolean):void
		{
			debug = enabled;
			info = enabled;
			warn = enabled;
			error = enabled;
			fatal = enabled;
		}

		public function get warn():Boolean
		{
			return _warn;
		}

		public function set warn(value:Boolean):void
		{
			if (_warn === value)
			{
				return;
			}

			if (value)
			{
				_level |= (1 << LogLevel.WARN);
			}
			else
			{
				_level &= ~(1 << LogLevel.WARN);
			}

			_warn = value;
			Logger.clearInternalCache();
		}

		public function write(time:Number, category:String, name:String, level:uint, message:String, args:Array):void
		{
			if (level > 4)
			{
				return;
			}
			if (_formatter === null)
			{
				_formatter = new LogFormatter(_format);
			}

			var logString:String = _formatter.format(time, category, name, level, message, args);
			writeString(level, name, logString);
		}

		protected function writeString(level:uint, name:String, logString:String):void
		{
		}
	}
}

import sweezy.core.log.LogLevel;
import sweezy.core.utils.Formatter;
import sweezy.core.utils.StringUtils;

class LogFormatter
{

	private static var _date:Date;

	private static var _logData:LogData;

	private var _format:String;

	private var _formatter:Formatter;

	private var _initialized:Boolean;

	public function LogFormatter(format:String)
	{
		_format = format;
	}

	public function format(time:Number, category:String, name:String, level:uint, message:String, args:Array):String
	{
		if (!_initialized)
		{
			_initialized = true;
			init();
		}

		if (message === null)
		{
			message = "";
		}
		else
		{
			message = StringUtils.format(message, args);
		}

		_date.time = time;

		_logData.year = String(_date.fullYear);
		_logData.month = _date.month < 9 ? ("0" + (_date.month + 1)) : String(_date.month + 1);
		_logData.date = _date.date < 10 ? ("0" + _date.date) : String(_date.date);
		_logData.hours = _date.hours < 10 ? ("0" + _date.hours) : String(_date.hours);
		_logData.minutes = _date.minutes < 10 ? ("0" + _date.minutes) : String(_date.minutes);
		_logData.seconds = _date.seconds < 10 ? ("0" + _date.seconds) : String(_date.seconds);
		_logData.milliseconds = _date.milliseconds < 10 ? ("00" + _date.milliseconds) : _date.milliseconds < 100 ? ("0" + _date.milliseconds) : String(_date.milliseconds);
		_logData.category = category;
		_logData.name = name;
		_logData.message = message;
		_logData.level = level > 4 ? "" : LogLevel.LOG_LEVEL_NAMES[level];

		return _formatter.format(_logData);
	}

	private function init():void
	{
		if (_date === null)
		{
			_date = new Date();
			_logData = new LogData();
		}

		if (!_format)
		{
			_format = "{year}-{month}-{date} {hours}:{minutes}:{seconds}.{milliseconds} [{level}] {message}";
		}

		_formatter = new Formatter(_format);
	}
}

dynamic class LogData
{

	public var category:String;

	public var date:String;

	public var hours:String;

	public var level:String;

	public var message:String;

	public var milliseconds:String;

	public var minutes:String;

	public var month:String;

	public var name:String;

	public var seconds:String;

	public var year:String;
}
